﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;

namespace ICommonLibrary {

    public class Util {

        private const string True = "true";
        private const string Yes = "yes";
        private const string False = "false";
        private const string No = "no";

        /// <summary>
        /// Regular expression of integer.
        /// </summary>
        public static readonly Regex IntPattern = new Regex(@"^(\+|-)?\d+$");

	    /// <summary>
        /// Regular expression of floating.
	    /// </summary>
        public static readonly Regex FloatPattern = new Regex(@"^(\+|-)?\d*\.\d+((E|e)(\+|-)?\d+)?$" + '|' +
                                                              @"^(\+|-)?\d+(\.)?(E|e)(\+|-)?\d+$" + '|' +
                                                              @"^(\+|-)?\d+\.$");

        /// <summary>
        /// Regular expression of floating number prefix.
        /// </summary>
        public static readonly Regex FloatPrefixPattern = new Regex(@"^(\+|-)?\d*\.\d+((E|e)(\+|-)?\d*)?$" + '|' +
                                                                    @"^(\+|-)?\d+(\.)?(E|e)(\+|-)?\d*$" + '|' +
                                                                    @"^(\+|-)?\d+\.$");
	    /// <summary>
        /// Regular expression of boolean.
	    /// </summary>
        public static readonly Regex BooleanPattern = new Regex("^true|false$");
	
	    /// <summary>
        /// Regular expression of white space.
	    /// </summary>
        public static readonly Regex WhitespacePattern = new Regex(@"^\s+$");
                
        /**
	     * hexdecimal digits
	     */
        public static readonly char[] HEX_DIGITS = 
            { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; 
        
        /**
	     * Random object used by Random method. This has to be not local to the
	     * Random method so as to not return the Same value in the Same millisecond.
	     */
        public static readonly Random RANDOM = new Random();

        /// <summary>
        /// Convert the word to have the first letter in uppercase and the others in lower case.
        /// </summary>
        /// <param name="word"></param>
        /// <returns></returns>
        public static string Capitalize(string word) {
            if (string.IsNullOrEmpty(word)) {
                return string.Empty;
            }

            char[] c = word.ToLower().ToCharArray();
            c[0] = char.ToUpper(c[0]);
            return new string(c);
        }
            
        /// <summary>
        /// Use the given n as base and returns a value that falls in the given range.
        /// </summary>
        /// <param name="n"></param>
        /// <param name="minInclusive"></param>
        /// <param name="maxInclusive"></param>
        /// <returns></returns>
	    public static double Clamp(double n, double minInclusive, double maxInclusive) {
		    Asserts.True(minInclusive <= maxInclusive, "min > max");
    		
		    return 	(n < minInclusive) ? minInclusive : 
				    (n > maxInclusive) ? maxInclusive : n;
	    }

        /// <summary>
        /// Use the given n as base and returns a value that falls in the given range.
        /// </summary>
        /// <param name="n"></param>
        /// <param name="minInclusive"></param>
        /// <param name="maxInclusive"></param>
        /// <returns></returns>
	    public static float Clamp(float n, float minInclusive, float maxInclusive) {
		    Asserts.True(minInclusive <= maxInclusive, "min > max");
    		
		    return 	(n < minInclusive) ? minInclusive : 
				    (n > maxInclusive) ? maxInclusive : n;
	    }
    	
	    /// <summary>
	    /// Use the given n as base and returns a value that falls in the given range.
	    /// </summary>
	    /// <param name="n"></param>
	    /// <param name="minInclusive"></param>
	    /// <param name="maxInclusive"></param>
	    /// <returns></returns>
	    public static int Clamp(int n, int minInclusive, int maxInclusive) {
		    Asserts.True(minInclusive <= maxInclusive, "min > max");
    		
		    return 	(n < minInclusive) ? minInclusive : 
				    (n > maxInclusive) ? maxInclusive : n;
	    }
        
        /// <summary>
        /// Use the given n as base and returns a value that falls in the given range.
        /// </summary>
        /// <param name="n"></param>
        /// <param name="minInclusive"></param>
        /// <param name="maxInclusive"></param>
        /// <returns></returns>
	    public static long Clamp(long n, long minInclusive, long maxInclusive) {
		    Asserts.True(minInclusive <= maxInclusive, "min > max");
    		
		    return 	(n < minInclusive) ? minInclusive : 
				    (n > maxInclusive) ? maxInclusive : n;
	    }	

	    /// <summary>
	    /// Use the given n as base and returns a value that falls in the given range.
	    /// </summary>
	    /// <param name="n"></param>
	    /// <param name="minInclusive"></param>
	    /// <param name="maxInclusive"></param>
	    /// <returns></returns>
	    public static short Clamp(short n, short minInclusive, short maxInclusive) {
		    Asserts.True(minInclusive <= maxInclusive, "min > max");
    		
		    return 	(n < minInclusive) ? minInclusive : 
				    (n > maxInclusive) ? maxInclusive : n;
	    }

	    /// <summary>
	    /// Compares two comparable objects -- allowing for null. Null values 
	    /// are considered to be the Same.
	    /// </summary>
	    /// <param name="o1"></param>
	    /// <param name="o2"></param>
	    /// <returns></returns>
	    public static int Compares(IComparable o1, IComparable o2) {
		    if (o1 == null && o2 == null)
			    return 0;
		    if (o1 == null)
			    return -1;
		    if (o2 == null)
			    return 1;
		    else
			    return o1.CompareTo(o2);
	    }

	    /// <summary>
        /// Compares two integer values.
	    /// </summary>
	    /// <param name="i1"></param>
	    /// <param name="i2"></param>
	    /// <returns></returns>
	    public static int Compares(int i1, int i2) {
		    return i1 - i2;
	    }

        /// <summary>Compares two objects.</summary>
        /// <param name="first">First object.</param>
        /// <param name="second">Second object.</param>
        /// <returns>
        /// 0, if objects are equal; 
        /// less than zero, if the first object is smaller than the second one;
        /// greater than zero, if the first object is greater than the second one.</returns>
        public static int Compare(object first, object second) {
            // anything is greater than null, unless both operands are null
            if (first == null) {
                return (second == null ? 0 : -1);
            }
            else if (second == null) {
                return 1;
            }

            if (!first.GetType().Equals(second.GetType())) {
                if (NumberUtil.IsNumber(first) && NumberUtil.IsNumber(second)) {
                    NumberUtil.CoerceTypes(ref second, ref first);
                }
                else {
                    throw new ArgumentException("Cannot compare instances of ["
                        + first.GetType().FullName
                        + "] and ["
                        + second.GetType().FullName
                        + "] because they cannot be coerced to the same type.");
                }
            }

            if (first is IComparable) {
                return ((IComparable)first).CompareTo(second);
            }
            else {
                throw new ArgumentException("Cannot compare instances of the type ["
                    + first.GetType().FullName
                    + "] because it doesn't implement IComparable");
            }
        }

	    /// <summary>
	    /// Compares two strings lexicographically, irrespective of case difference,
	    /// and allowing for null. Null values are considered to be the same.
	    /// </summary>
	    /// <param name="left"></param>
	    /// <param name="right"></param>
	    /// <returns></returns>
        public static int ComparesIgnoreCase(string left, string right) {
		    return 	(left == null && right == null) ? 0 :
				    (left != null && right == null) ? 1 :
				    (left == null && right != null)	? -1  : string.Compare(left, right, true);
        }

	    /// <summary>
	    /// Tests whether its two arguments are equal -- allowing for null. Null values 
	    /// are considered to be the same.
	    /// </summary>
	    /// <param name="o1"></param>
	    /// <param name="o2"></param>
	    /// <returns></returns>
        public new static bool Equals(object o1, object o2) {
    	    if (o1 == null)
    		    return o2 == null;
   		    if (o2 == null)
   			    return false;
		    if (o1.GetType().IsArray && o2.GetType().IsArray)
			    return ArrayUtil.Equals((Array)o1, (Array)o2);
		    else
			    return o1.Equals(o2);
	    }
    	
	    /// <summary>
	    /// Tests whether the two strings are equal lexicographically, irrespective
	    /// of case difference, and allowing for null (two null values are considered
	    /// to be equal).
	    /// </summary>
	    /// <param name="s1"></param>
	    /// <param name="s2"></param>
	    /// <returns></returns>
	    public static bool EqualsIgnoreCase(string s1, string s2) {
		    return	(s1 == null && s2 == null) ? true :
				    (s1 != null) ? s1.Equals(s2, StringComparison.OrdinalIgnoreCase) : false;
	    }

	    /// <summary>
	    /// Tests the string presentation of the first argument. Returns true if it
	    /// Equals "true" or "yes"; returns false if it Equals "false" or "no", 
	    /// irrespective of case; returns the second argument otherwise.
	    /// </summary>
	    /// <param name="o"></param>
	    /// <param name="def"></param>
	    /// <returns></returns>
	    public static bool GetBool(object o, bool def) {
		    if (o == null)
			    return def;
    	
		    string s = o.ToString();
		    if (s == null)
			    return def;
    		
		    s = s.ToLowerInvariant();
    		
		    if (s.Equals(True) || 
			    s.Equals(Yes)) {
			    return true;
		    } 
		    if (s.Equals(False) || 
				s.Equals(No)) {
			    return false;
		    } 
    	    return def;
	    }

        /// <summary>
        /// Tests the string presentation of the first argument. Returns true if it 
        /// Equals "true", "yes" or "on"; returns false if it Equals "false", "no" or 
        /// "off", irrespective of case; returns the second argument otherwise.
        /// </summary>
        /// <param name="o"></param>
        /// <param name="def"></param>
        /// <returns></returns>
        public static bool? GetBoolNull(object o, bool? def) {
            if (o == null)
                return def;

            string s = o.ToString();
            if (string.IsNullOrEmpty(s))
                return def;

            s = s.ToLowerInvariant();

            if (s.Equals(True) ||
                s.Equals(Yes)) {
                return true;
            }
            if (s.Equals(False) ||
                s.Equals(No)) {
                return false;
            }
            return def;
        }

	    /// <summary>
        /// Returns the result of Convert.ToByte(o), or the default
        /// value if any error occured.
	    /// </summary>
	    /// <param name="o"></param>
	    /// <param name="def"></param>
	    /// <returns></returns>
	    public static byte GetByte(object o, byte def) {
		    if (o == null)
			    return def;

            if (o is byte) {
                return (byte)o;
            }

	        string s = o.ToString();
            if (string.IsNullOrEmpty(s)) {
                return def;
            }

            byte b;
            if (byte.TryParse(s, out b)) {
                return b;
            }
            return def;
	    }

	    /// <summary>
        /// Returns the result of o.ToString()[0], or the default
        /// value if any error occured.
	    /// </summary>
	    /// <param name="o"></param>
	    /// <param name="def"></param>
	    /// <returns></returns>
	    public static char GetChar(object o, char def) {
		    if (o == null)
			    return def;

		    string s = o.ToString();
		    if (s.Length == 0) {
			    return def;
		    } 
    	    return s[0];
	    }
    	
	    /// <summary>
        /// Returns the result of Convert.ToDouble(o.ToString()), or the default
        /// value if any error occured.
	    /// </summary>
	    /// <param name="o"></param>
	    /// <param name="def"></param>
	    /// <returns></returns>
	    public static double GetDouble(object o, double def) {
		    if (o == null)
			    return def;

            if (o is double) {
                return (double) o;
            }

            string s = o.ToString();
            if (string.IsNullOrEmpty(s)) {
                return def;
            }

            double d;
            if (double.TryParse(s, out d)) {
                return d;
            }
    	    return def;
	    }

        /// <summary>
        /// Returns the result of Convert.ToDouble(o.ToString()), or the default
        /// value if any error occured.
	    /// </summary>
	    /// <param name="o"></param>
	    /// <param name="def"></param>
	    /// <returns></returns>
	    public static double? GetDoubleNull(object o, double? def) {
		    if (o == null)
			    return def;

            if (o is double) {
                return (double)o;
            }
            
            string s = o.ToString();
            if (string.IsNullOrEmpty(s)) {
                return def;
            }

            double d;
            if (double.TryParse(s, out d)) {
                return d;
            }
    	    return def;
	    }

        public static T GetEnum<T>(object o, T def) {
            int? i = GetIntNull(o, null);
            if (i == null) {
                return def;
            }

            if (Enum.IsDefined(typeof(T), i.Value)) {
                return (T) (object) i.Value;
            }
            return def;
        }

        /// <summary>
        /// Returns the result of Convert.ToInt32(o.ToString()), or the default
        /// value if any error occured.
        /// </summary>
        /// <param name="o"></param>
        /// <param name="def"></param>
        /// <returns></returns>
        public static int GetInt(object o, int def) {
		    if (o == null)
			    return def;

            if (o is int) {
                return (int)o;
            }

            string s = o.ToString();
            if (string.IsNullOrEmpty(s)) {
                return def;
            }

            int i;
            if (int.TryParse(s, out i)) {
                return i;
            }

            return def;
	    }

        /// <summary>
        /// Returns the result of Convert.ToInt32(o.ToString()), or the default
        /// value if any error occured.
        /// </summary>
        /// <param name="o"></param>
        /// <param name="def"></param>
        /// <returns></returns>
        public static int? GetIntNull(object o, int? def) {
		    if (o == null)
			    return def;

            if (o is int) {
                return (int)o;
            }

            string s = o.ToString();
            if (string.IsNullOrEmpty(s)) {
                return def;
            }

            int i;
            if (int.TryParse(s, out i)) {
                return i;
            }
            return def;
	    }
    	
        /// <summary>
        /// Returns the result of Convert.ToInt64(o.ToString()), or the default
        /// value if any error occured.
        /// </summary>
        /// <param name="o"></param>
        /// <param name="def"></param>
        /// <returns></returns>
	    public static long GetLong(object o, long def) {
		    if (o == null)
			    return def;

            if (o is long) {
                return (long)o;
            }

            string s = o.ToString();
            if (string.IsNullOrEmpty(s)) {
                return def;
            }

            long l;
            if (long.TryParse(s, out l)) {
                return l;
            }
            return def;
	    }

        /// <summary>
        /// Returns the result of Convert.ToInt64(o.ToString()), or the default
        /// value if any error occured.
        /// </summary>
        /// <param name="o"></param>
        /// <param name="def"></param>
        /// <returns></returns>
        public static long? GetLongNull(object o, long? def) {
            if (o == null)
                return def;

            if (o is long) {
                return (long)o;
            }

            string s = o.ToString();
            if (string.IsNullOrEmpty(s)) {
                return def;
            }

            long l;
            if (long.TryParse(s, out l)) {
                return l;
            }
            return def;
        }
    	
	    /// <summary>
        /// Returns the result of Short.parseShort(o.ToString()), or the default
        /// value if any error occured.
	    /// </summary>
	    /// <param name="o"></param>
	    /// <param name="def"></param>
	    /// <returns></returns>
	    public static short GetShort(object o, short def) {
		    if (o == null)
			    return def;

            if (o is short) {
                return (short)o;
            }

            string s = o.ToString();
            if (string.IsNullOrEmpty(s)) {
                return def;
            }

            short n;
            if (short.TryParse(s, out n)) {
                return n;
            }
            return def;
	    }

        /// <summary>
        /// Returns the given string, or an empty string if the given string 
        /// is null.
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static string GetString(string s) {
            return s ?? string.Empty;
        }

	    /// <summary>
	    /// Returns the result of o.ToString(), or an empty string if the object 
	    /// is null.
	    /// </summary>
	    /// <param name="o"></param>
	    /// <returns></returns>
	    public static string GetString(object o) {
		    return (o == null) ? string.Empty : o.ToString();
	    }

        /// <summary>
        /// Returns the given string, or the default value if the given string 
        /// is null.
        /// </summary>
        /// <param name="s"></param>
        /// <param name="def"></param>
        /// <returns></returns>
        public static string GetString(string s, string def) {
            return s ?? def;
        }

        /// <summary>
        /// Returns the result of o.ToString(), or the default value if the object 
        /// is null.
        /// </summary>
        /// <param name="o"></param>
        /// <param name="def"></param>
        /// <returns></returns>
	    public static string GetString(object o, string def) {
		    return (o == null) ? def : o.ToString();
	    }

        /// <summary>
        /// Returns the result of s.Trim(), or an empty string if <see cref="s"/>
        /// is null.
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static string GetTrimString(string s) {
            return (s == null) ? string.Empty : s.Trim();
        }

        /// <summary>
	    /// Returns the result of o.ToString().Trim(), or an empty string if 
	    /// <see cref="o"/> is null.
	    /// </summary>
	    /// <param name="o"></param>
	    /// <returns></returns>
	    public static string GetTrimString(object o) {
		    return (o == null) ? string.Empty : o.ToString().Trim();
	    }

        /// <summary>
        /// Returns the hash code of the given object, or 0 if the object is null.
        /// </summary>
        /// <param name="o"></param>
        /// <returns></returns>
	    public static int GetHashCode(object o) {
		    return o == null ? 0 : o.GetHashCode();
	    }
        
	    /// <summary>
	    /// Returns the hash code of the given array, or 0 if the array is null.
	    /// </summary>
	    /// <param name="a"></param>
	    /// <returns></returns>
        public static int GetHashCode(object[] a) {
		    if (a == null)
			    return 0;
		    int hashCode = 89;
		    for (int i = 0; i < a.Length; i++) {
			    object o = a[i];
			    if (o != null)
				    hashCode = hashCode * 31 + o.GetHashCode();
		    }
		    return hashCode;
	    }

	    /// <summary>
	    /// This method is equivalent to
	    ///     str.ToLowerInvariant().IndexOf(substring.ToLowerInvariant());
	    /// </summary>
	    /// <param name="str"></param>
	    /// <param name="substring"></param>
	    /// <returns></returns>

	    public static int IndexOfIgnoreCase(string str, string substring) {
		    return str.ToLowerInvariant().IndexOf(substring.ToLowerInvariant());
	    }

        /// <summary>
        /// This method is similar to
        /// 
        ///     str.ToLowerInvariant().IndexOf(Substring.ToLowerInvariant(), from);
        /// 
        /// but it never throws OutOfBoundException even if the from vaue is out
        /// of bound of the string. 
        /// </summary>
        /// <param name="str"></param>
        /// <param name="substring"></param>
        /// <param name="from"></param>
        /// <returns></returns>
        public static int IndexOfIgnoreCase(string str, string substring, int from) {
            string strLower = str.ToLowerInvariant();
            string substrLower = substring.ToLowerInvariant();
            return strLower.IndexOf(substrLower, Clamp(from, 0, strLower.Length - 1));
        }

        /// <summary>
        /// Returns whether the given string represents an escape char (e.g. \n, \t,
        /// \r, \\, etc.)
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static bool IsEscapeChar(string s) {
		    if (s.Length  != 2 || s[0] != '\\')
			    return false;
    		
		    char c = s[1];
		    return c == '\\' || c == 'b' || c == 'f' || c == 'n' ||
			       c == 'r'  || c == 't' || c == '\''|| c == '"';
	    }

	    /// <summary>
        /// Returns true if the given string is null or empty, false otherwise.
	    /// </summary>
	    /// <param name="s"></param>
	    /// <returns></returns>
	    public static bool IsBlank(string s) {
		    return string.IsNullOrEmpty(s);
	    }

	    /// <summary>
        /// Return true if the given string is neither null nor empty, false otherwise.
	    /// </summary>
	    /// <param name="s"></param>
	    /// <returns></returns>
	    public static bool NotBlank(string s) {
		    return (!IsBlank(s));
	    }

	    /// <summary>
	    /// Creates a Random string based on a variety of options, using supplied
	    /// source of randomness.
	    /// 
	    /// If start and end are both 0, start and end are set to
	    /// ' ' and 'z', the ASCII printable characters, will be used, unless letters 
	    /// and numbers are both* false, in which case, start and end are set to
	    /// 0 and Integer.MAX_VALUE.
	    /// 
	    /// If set is not null, characters between start and end are chosen.
	    /// 
	    /// This method accepts a user-supplied {@link Random} instance to use as a
	    /// source of randomness. By seeding a single {@link Random} instance with a 
	    /// fixed seed and using it for each call, the Same Random sequence of 
	    /// strings can be generated repeatedly and predictably.
	    /// </summary>
        /// <param name="count">the length of Random string to create</param>
        /// <param name="start">the position in set of chars to start at</param>
        /// <param name="end">the position in set of chars to end before</param>
        /// <param name="letters">only allow letters?</param>
        /// <param name="numbers">only allow numbers?</param>
	    /// <param name="chars">the set of chars to choose randoms from. If null, 
	    /// then it will use the set of all chars.</param>
        /// <param name="random">a source of randomness.</param>
        /// <returns>the Random string</returns>
	    public static string Random(int count, int start, int end, bool letters,
		    bool numbers, char[] chars, Random random) {
    		
		    if (count == 0) {
			    return string.Empty;
		    } 
		    else if (count < 0) {
			    throw new Exception("Requested Random string length " + count + " is less than 0.");
		    }

		    if ((start == 0) && (end == 0)) {
			    end = 'z' + 1;
			    start = ' ';

			    if (!letters && !numbers) {
				    start = 0;
				    end = int.MaxValue;
			    }
		    }

		    StringBuilder buffer = new StringBuilder();
		    int gap = end - start;

		    while (count-- != 0) {
			    char ch;

			    if (chars == null) {
				    ch = (char) (random.Next((gap) + start));
			    } else {
				    ch = chars[random.Next(gap) + start];
			    }

			    if ((letters && numbers && char.IsLetterOrDigit(ch))
					    || (letters && char.IsLetter(ch))
					    || (numbers && char.IsDigit(ch))
					    || (!letters && !numbers)) {
				    buffer.Append(ch);
			    } else {
				    count++;
			    }
		    }

		    return buffer.ToString();
	    }
    	
        /// <summary>
        /// Generate a Random string based on the given pattern. Occurance of '_' in
        /// the pattern is to be replaced by a Random alphabetic character, occurance 
        /// of '#' is to be replaced by a Random digit. All other characters retain.
        /// 
        /// For example, pattern "___, #### is your lucky number" may produce "XYZ, 
        /// 3435 is your lucky number"
        /// </summary>
        /// <param name="pattern"></param>
        /// <returns></returns>
	    public static string Random(string pattern) {
		    StringBuilder b = new StringBuilder(pattern.Length);
		    for (int i = 0; i < pattern.Length; i++) {
			    char c = pattern[i];
			    if (c == '_') {
				    char a = RANDOM.Next(1) == 0? 'a' : 'A';
				    int inc = Math.Abs(RANDOM.Next(int.MaxValue) % 26);
				    int kk = a + (inc);
				    b.Append((char)(kk));
			    }
			    else if (c == '#') {
				    b.Append((char)('0' + Math.Abs(RANDOM.Next(int.MaxValue)) % 10));
			    }
			    else {
				    b.Append(c);
			    }
		    }
		    return b.ToString();
	    }

	    /// <summary>
        /// Creates a string of fixed size with Random alphebetic content.
	    /// </summary>
	    /// <param name="size"></param>
	    /// <returns></returns>
	    public static string RandomAlphabetic(int size) {
		    return Random(size, 0, 0, true, false, null, RANDOM);
	    }

        public static List<string> SplitByLength(string s, int length) {
            if (s.Length == 0) {
                return new List<string> {""};
            }

            var segments = new List<string>();
            while (s.Length > 0) {
                int segementLength = Math.Min(length, s.Length);
                segments.Add(s.Substring(0, segementLength));
                
                if (segementLength == s.Length) {
                    break;
                }
                s = s.Substring(segementLength);
            }
            return segments;
        }
    	
	    /// <summary>
	    /// This method is a safer replacement of string.Substring(). It returns
	    ///    
	    ///    * null if the s is null
	    ///    * an empty string if the length of the s is smaller than the beginIndex
	    ///    * s.Substring(beginIndex, s.Length) if the endIndex is larger than the length of the s
	    ///    * s.Substring(beginIndex, endIndex) otherwise
	    /// </summary>
	    /// <param name="s"></param>
	    /// <param name="beginIndex"></param>
	    /// <param name="endIndex"></param>
	    /// <returns></returns>
	    public static string Substring(string s, int beginIndex, int endIndex) {
		    if (s == null) 
			    return null;
		    beginIndex = Math.Max(beginIndex, 0);
		    if (beginIndex > s.Length || endIndex < beginIndex)
			    return string.Empty;
		    if (endIndex > s.Length)
			    return s.Substring(beginIndex);

		    return s.Substring(beginIndex, endIndex - beginIndex);
	    }
    	
	    public static char ToEscapeChar(string str) {
		    Asserts.Equals('\\', str[0]);
		    switch(str[1]) {
			    case '\\':	return '\\';
			    case 'b':	return '\b';
			    case 'f':	return '\f';
			    case 'n':	return '\n';
			    case 'r':	return '\r';
			    case 't':	return '\t';
			    case '\'':	return '\'';
			    case '"':	return '"';
		    }
		    throw new Exception("illegal escape char");
	    }
    	

        /// <summary>
        /// Converts the lowest order four bytes of an integer 
        /// to a hex char (0-9A-F).
        /// </summary>
        /// <param name="nibble"></param>
        /// <returns>a hex char (0-9A-F)</returns>
        private static char ToHex(int nibble) {
            return HEX_DIGITS[nibble & 0xF];
        }
        
        /// <summary>
        /// Returns the specified string converted to a format suitable for HTML. All
        /// signle-quote, double-quote, greater-than, less-than and ampersand 
        /// characters are replaces with their corresponding HTML Character Entity 
        /// code. If the given string is null, the method returns an empty string.
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static string ToHTMLString(string s) {
    	    if (s == null)
    		    return string.Empty;
        	
            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < s.Length; i++) {
                char c = s[i];
                if (c == '\'') {
                    builder.Append("&#039;");
                }
                else if (c == '\"') {
                    builder.Append("&#034;");
                }
                else if (c == '<') {
                    builder.Append("&lt;");
                }
                else if (c == '>') {
                    builder.Append("&gt;");
                }
                else if (c == '&') {
                    builder.Append("&amp;");
                }
                else {
                    builder.Append(c);
                }
            }
            return builder.ToString();
        }
        
        /// <summary>
        /// Returns a string with all excape characters converted to unicode.
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static string ToUnicodeEscapeString(string str) {
            StringBuilder buf = new StringBuilder();
            int len = str.Length;
            for (int i = 0; i < len; i++) {
                char ch = str[i];
                switch (ch) {
                    case '\\': buf.Append("\\\\"); break;
                    case '\t': buf.Append("\\t");  break;
                    case '\n': buf.Append("\\n");  break;
                    case '\r': buf.Append("\\r");  break;
                    default:
                        if (ch >= ' ' && ch <= 127) {
                            buf.Append(ch);
                        }
                        else {
                            buf.Append('\\');
                            buf.Append('u');
                            buf.Append(ToHex( (ch >> 12) & 0xF));
                            buf.Append(ToHex( (ch >> 8) & 0xF));
                            buf.Append(ToHex( (ch >> 4) & 0xF));
                            buf.Append(ToHex( (ch >> 0) & 0xF));
                        }
                        break;
                }
            }
            return buf.ToString();
        }

        /// <summary>
        /// Returns the specified string converted to a format suitable for XML. All
        /// signle-quote, double-quote, greater-than, less-than and ampersand
        /// characters are replaces with their corresponding XML Character Entity
        /// code. If the given string is null, the method returns an empty string.
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static string ToXMLString(string s) {
    	    if (s == null)
    		    return string.Empty;

    	    StringBuilder result = null;
		    for (int i = 0, max = s.Length, delta = 0; i < max; i++) {
			    char c = s[i];
			    string replacement = null;

			    if (c == '&') {
				    replacement = "&amp;";
			    } else if (c == '<') {
				    replacement = "&lt;";
			    } else if (c == '\r') {
				    replacement = "&#13;";
			    } else if (c == '>') {
				    replacement = "&gt;";
			    } else if (c == '"') {
				    replacement = "&quot;";
			    } else if (c == '\'') {
				    replacement = "&apos;";
			    }

			    if (replacement != null) {
				    if (result == null) {
					    result = new StringBuilder(s);
				    }
				    result.Replace(c.ToString(), replacement, i + delta, 1);
				    delta += (replacement.Length - 1);
			    }
		    }
		    if (result == null) {
			    return s;
		    }
		    return result.ToString();
	    }

        public static string Trim(string s) {
            return s == null ? s : s.Trim();
        }

        public static void TrimAll(string[] s) {
            int total = s.Length;
            for (int i = 0; i < total; i++) {
                s[i] = Trim(s[i]);
            }
        }
    }
}
